package com.kuaiyin.utils;

import com.kuaiyin.config.MinioConfig;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import io.minio.http.Method;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;

@Slf4j
@Component
public class MinioUploadUtil {

    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    @Autowired
    private MinioClient minioClient;

    @Autowired
    private MinioConfig minioConfig;

    @Autowired
    @Qualifier("minioUploadThreadPool")
    private ExecutorService executorService;

    //====================== 同步上传 ======================

    /**
     * 同步上传文件（自动生成带时间戳和UUID的文件名）
     * @param file 上传的文件
     * @param prefix 文件前缀（如：user/avatar/）
     * @return 文件访问URL
     */
    public String uploadWithAutoName(MultipartFile file, String prefix) throws MinioException {
        String objectName = generateUniqueName(prefix, file.getOriginalFilename());
        return uploadSync(file, objectName);
    }

    /**
     * 同步上传文件（指定完整对象名）
     */
    public String uploadSync(MultipartFile file, String objectName) throws MinioException {
        try (InputStream stream = file.getInputStream()) {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(minioConfig.getBucketName())
                            .object(objectName)
                            .stream(stream, file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build());

            return getFileUrl(objectName);
        } catch (Exception e) {
            log.error("MinIO同步上传失败: {}", e.getMessage());
            throw new MinioException("文件上传失败: " + e.getMessage());
        }
    }

    //====================== 异步上传 ======================

    /**
     * 异步上传（自动生成文件名）
     */
    public CompletableFuture<String> uploadAsyncWithAutoName(MultipartFile file, String prefix) {
        String objectName = generateUniqueName(prefix, file.getOriginalFilename());
        return uploadAsync(file, objectName);
    }

    /**
     * 异步上传（指定对象名）
     */
    public CompletableFuture<String> uploadAsync(MultipartFile file, String objectName) {
        return CompletableFuture.supplyAsync(() -> {
            try {
                return uploadSync(file, objectName);
            } catch (MinioException e) {
                throw new RuntimeException(e);
            }
        }, executorService);
    }

    //====================== 文件名处理 ======================

    /**
     * 生成唯一文件名（格式：prefix/yyyyMMddHHmmss_uuid.扩展名）
     */
    private String generateUniqueName(String prefix, String originalFilename) {
        String timestamp = LocalDateTime.now().format(DATE_FORMAT);
        String uuid = UUID.randomUUID().toString().replace("-", "").substring(0, 8);

        // 处理原始文件名获取扩展名
        String extension = "";
        if (originalFilename != null && originalFilename.contains(".")) {
            extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        }

        // 标准化前缀（确保以/结尾）
        String normalizedPrefix = prefix.endsWith("/") ? prefix : prefix + "/";

        return String.format("%s%s_%s%s", normalizedPrefix, timestamp, uuid, extension);
    }

    //====================== 辅助方法 ======================

    private String getFileUrl(String objectName) throws Exception {
        return minioClient.getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(minioConfig.getBucketName())
                        .object(objectName)
                        .build());
    }

    //====================== 自定义异常 ======================
    public static class MinioException extends RuntimeException {
        public MinioException(String message) {
            super(message);
        }
    }
}